﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using IPC.Communication.BasicFramework;
using IPC.Communication.Core.Net;
using IPC.Communication.Reflection;

namespace IPC.Communication.Profinet.Panasonic
{
    public class PanasonicMewtocolServer : NetworkDataServerBase
    {
        private SerialPort serialPort;

        private SoftBuffer xBuffer;

        private SoftBuffer rBuffer;

        private SoftBuffer dBuffer;

        private SoftBuffer lBuffer;

        private SoftBuffer fBuffer;

        private const int DataPoolLength = 65536;

        private byte station = 1;

        public byte Station
        {
            get
            {
                return station;
            }
            set
            {
                station = value;
            }
        }

        public PanasonicMewtocolServer()
        {
            rBuffer = new SoftBuffer(131072);
            dBuffer = new SoftBuffer(131072);
        }

        protected override byte[] SaveToBytes()
        {
            byte[] array = new byte[262144];
            Array.Copy(rBuffer.GetBytes(), 0, array, 0, 131072);
            Array.Copy(dBuffer.GetBytes(), 0, array, 131072, 131072);
            return array;
        }

        protected override void LoadFromBytes(byte[] content)
        {
            if (content.Length < 262144)
            {
                throw new Exception("File is not correct");
            }
            rBuffer.SetBytes(content, 0, 0, 131072);
            dBuffer.SetBytes(content, 131072, 0, 131072);
        }

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
        }

        [HslMqttApi("ReadBoolArray", "")]
        public override OperateResult<bool[]> ReadBool(string address, ushort length)
        {
            return new OperateResult<bool[]>(StringResources.Language.NotSupportedDataType);
        }

        [HslMqttApi("WriteBoolArray", "")]
        public override OperateResult Write(string address, bool[] value)
        {
            return new OperateResult<byte[]>(StringResources.Language.NotSupportedDataType);
        }

        //protected override void ThreadPoolLoginAfterClientCheck(Socket socket, IPEndPoint endPoint)
        //{
        //    AppSession appSession = new AppSession();
        //    appSession.IpEndPoint = endPoint;
        //    appSession.WorkSocket = socket;
        //    if (socket.BeginReceiveResult(SocketAsyncCallBack, appSession).IsSuccess)
        //    {
        //        AddClient(appSession);
        //    }
        //    else
        //    {
        //        base.LogNet?.WriteDebug(ToString(), string.Format(StringResources.Language.ClientOfflineInfo, endPoint));
        //    }
        //}

        //[AsyncStateMachine(typeof(<SocketAsyncCallBack>d__11))]
        //[DebuggerStepThrough]
        //private void SocketAsyncCallBack(IAsyncResult ar)
        //{
        //    <SocketAsyncCallBack>d__11 stateMachine = new <SocketAsyncCallBack>d__11();
        //    stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.ar = ar;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //}

        protected string CreateFailedResponse(byte code)
        {
            return "!" + code.ToString("D2");
        }

        public virtual string ReadFromCommand(byte[] cmd)
        {
            try
            {
                string @string = Encoding.ASCII.GetString(cmd);
                if (@string[0] != '%')
                {
                    return CreateFailedResponse(41);
                }
                byte b = Convert.ToByte(@string.Substring(1, 2), 16);
                if (b != station)
                {
                    if (base.LogNet != null)
                    {
                        base.LogNet.WriteError(ToString(), String.Format("Station not match, need:{0}, but now: {1}", station, b));
                    }
                    return CreateFailedResponse(50);
                }
                if (@string[3] != '#')
                {
                    return CreateFailedResponse(41);
                }
                if (@string.Substring(4, 3) == "RCS")
                {
                    if (@string[7] == 'R')
                    {
                        int destIndex = Convert.ToInt32(@string.Substring(8, 3)) * 16 + Convert.ToInt32(@string.Substring(11, 1), 16);
                        bool @bool = rBuffer.GetBool(destIndex);
                        return "$RC" + (@bool ? "1" : "0");
                    }
                }
                else if (@string.Substring(4, 3) == "WCS" && @string[7] == 'R')
                {
                    int destIndex2 = Convert.ToInt32(@string.Substring(8, 3)) * 16 + Convert.ToInt32(@string.Substring(11, 1), 16);
                    rBuffer.SetBool(@string[12] == '1', destIndex2);
                    return "$WC";
                }
                if (@string.Substring(4, 3) == "RCC")
                {
                    if (@string[7] == 'R')
                    {
                        int num = Convert.ToInt32(@string.Substring(8, 4));
                        int num2 = Convert.ToInt32(@string.Substring(12, 4));
                        int num3 = num2 - num + 1;
                        byte[] bytes = rBuffer.GetBytes(num * 2, num3 * 2);
                        return "$RC" + bytes.ToHexString();
                    }
                }
                else if (@string.Substring(4, 3) == "WCC" && @string[7] == 'R')
                {
                    int num4 = Convert.ToInt32(@string.Substring(8, 4));
                    int num5 = Convert.ToInt32(@string.Substring(12, 4));
                    int num6 = num5 - num4 + 1;
                    byte[] data = @string.Substring(16, num6 * 4).ToHexBytes();
                    rBuffer.SetBytes(data, num4 * 2);
                    return "$WC";
                }
                if (@string.Substring(4, 2) == "RD")
                {
                    if (@string[6] == 'D')
                    {
                        int num7 = Convert.ToInt32(@string.Substring(7, 5));
                        int num8 = Convert.ToInt32(@string.Substring(12, 5));
                        int num9 = num8 - num7 + 1;
                        byte[] bytes2 = dBuffer.GetBytes(num7 * 2, num9 * 2);
                        return "$RD" + bytes2.ToHexString();
                    }
                }
                else if (@string.Substring(4, 2) == "WD" && @string[6] == 'D')
                {
                    int num10 = Convert.ToInt32(@string.Substring(7, 5));
                    int num11 = Convert.ToInt32(@string.Substring(12, 5));
                    int num12 = num11 - num10 + 1;
                    byte[] data2 = @string.Substring(17, num12 * 4).ToHexBytes();
                    dBuffer.SetBytes(data2, num10 * 2);
                    return "$WD";
                }
                return CreateFailedResponse(41);
            }
            catch
            {
                return CreateFailedResponse(41);
            }
        }

        public void StartModbusRtu(string com)
        {
            StartModbusRtu(com, 9600);
        }

        public void StartModbusRtu(string com, int baudRate)
        {
            StartModbusRtu(delegate(SerialPort sp)
            {
                sp.PortName = com;
                sp.BaudRate = baudRate;
                sp.DataBits = 8;
                sp.Parity = Parity.None;
                sp.StopBits = StopBits.One;
            });
        }

        public void StartModbusRtu(Action<SerialPort> inni)
        {
            if (!serialPort.IsOpen)
            {
                if (inni != null)
                {
                    inni.Invoke(serialPort);
                }
                serialPort.ReadBufferSize = 1024;
                serialPort.ReceivedBytesThreshold = 1;
                serialPort.Open();
                serialPort.DataReceived += SerialPort_DataReceived;
            }
        }

        public void CloseModbusRtu()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int num = 0;
            byte[] array = new byte[1024];
            int num2;
            do
            {
                Thread.Sleep(20);
                num2 = serialPort.Read(array, num, serialPort.BytesToRead);
                num += num2;
            }
            while (num2 != 0);
            if (num == 0)
            {
                return;
            }
            byte[] array2 = array.SelectBegin(num);
            if (array2.Length < 5)
            {
                if (base.LogNet != null)
                {
                    base.LogNet.WriteError(ToString(), "[" + serialPort.PortName + "] Uknown Data：" + array2.ToHexString(' '));
                }
                return;
            }
            if (base.LogNet != null)
            {
                base.LogNet.WriteDebug(ToString(), "[" + serialPort.PortName + "] Rtu " + StringResources.Language.Receive + "：" + array2.ToHexString(' '));
            }
            byte[] content = PanasonicHelper.PackPanasonicCommand(station, ReadFromCommand(array2)).Content;
            serialPort.Write(content, 0, content.Length);
            if (base.LogNet != null)
            {
                base.LogNet.WriteDebug(ToString(), "[" + serialPort.PortName + "] Rtu " + StringResources.Language.Send + "：" + content.ToHexString(' '));
            }
            if (base.IsStarted)
            {
                RaiseDataReceived(sender, array2);
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (rBuffer != null)
                {
                    rBuffer.Dispose();
                }
                if (dBuffer != null)
                {
                    dBuffer.Dispose();
                }
                if (serialPort != null)
                {
                    serialPort.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        public override string ToString()
        {
            return String.Format("PanasonicMewtocolServer[{0}]", base.Port);
        }
    }
}